package xddq

import (
	"fmt"
	"math/rand"
	"time"
	D "websocket_apn/define"
	"websocket_apn/log"
	"websocket_apn/proto"
)

// FindNextUncharted 查找下一个未探索的坐标
// 返回值: (found bool, moveTo D.Point, target D.Point)
// found - 是否找到未探索点
// moveTo - 需要移动到的位置
// target - 未探索的目标位置
func FindNextUncharted(allInfo D.WeYoundInfo) (bool, D.Point, D.Point) {
	// 1. 首先在当前列查找未探索的点
	if found, moveTo, target := findInColumn(allInfo.X, allInfo.Y, allInfo.Point); found {
		return true, moveTo, target
	}

	// 2. 当前列没有未探索点，尝试相邻列
	// 这里可以根据需求决定是先向左还是向右搜索
	// 示例中我们先尝试X-1列，再尝试X+1列

	// 尝试X-1列
	if allInfo.X > 0 {
		if found, moveTo, target := findInColumn(allInfo.X-1, allInfo.Y, allInfo.Point); found {
			return true, moveTo, target
		}
	}

	// 尝试X+1列
	if found, moveTo, target := findInColumn(allInfo.X+1, allInfo.Y, allInfo.Point); found {
		return true, moveTo, target
	}

	// 所有可能的方向都探索完毕
	return false, D.Point{}, D.Point{}
}

// findInColumn 在指定列中查找未探索的点
func findInColumn(x, currentY byte, points []D.Point) (bool, D.Point, D.Point) {
	// 收集当前列的所有Y坐标
	var columnYs []byte
	for _, p := range points {
		if p.X == x {
			columnYs = append(columnYs, p.Y)
		}
	}

	// 如果没有探索过任何点，直接返回(0,0)
	if len(columnYs) <= 1 {
		return true, D.Point{x, currentY}, D.Point{x, currentY - 1}
	}
	start := columnYs[0]
	end := columnYs[len(columnYs)-1]
	//log.Infof("%s\n(%02X,%02X)-(%02X,%02X)", proto.HexToHexStr(columnYs), x, start, x, end)

	if rand.Intn(2) == 0 { // 50%概率先向上搜索
		// 向上搜索
		for y := currentY - 1; y >= start; y-- {
			if !containsY(columnYs, y) {
				return true, D.Point{x, y + 1}, D.Point{x, y}
			}
		}
		// 向上搜索无结果，再向下搜索
		for y := currentY + 1; y < end; y++ {
			if !containsY(columnYs, y) {
				return true, D.Point{x, y - 1}, D.Point{x, y}
			}
		}
	} else { // 50%概率先向下搜索
		// 向下搜索
		for y := currentY + 1; y < end; y++ {
			if !containsY(columnYs, y) {
				return true, D.Point{x, y - 1}, D.Point{x, y}
			}
		}
		// 向下搜索无结果，再向上搜索
		for y := currentY - 1; y >= start; y-- {
			if !containsY(columnYs, y) {
				return true, D.Point{x, y + 1}, D.Point{x, y}
			}
		}
	}
	// 当前列全部已探索
	return false, D.Point{}, D.Point{}
}

// containsY 检查Y坐标是否存在于切片中
func containsY(ys []byte, y byte) bool {
	for _, v := range ys {
		if v == y {
			return true
		}
	}
	return false
}

// 处理未央仙境信息
func (xd *XdDriver) CheckWeYoundInfoData(allInfo D.WeYoundInfo) {
	lefTime := int32(xd.UserData.Activity[D.Activity_We_Yound_Scene].EndTime.Sub(time.Now()).Hours())
	log.Infof("未央仙境-当前关卡%d, 当前剩余体力%d, 当前灵力%d, 积分%d, 位置（%02X,%02X）,活动剩余%d小时",
		allInfo.Level, allInfo.Strength, allInfo.Spirit, allInfo.Points, allInfo.X, allInfo.Y, lefTime)
	if allInfo.NextFloor {
		log.Infof("未央仙境-下一岛屿已开放，开始前往")
		xd.Send(proto.Get_Cmd_Data(xd.userInfo.PlayerId, proto.S_WE_YOUND_RED_POINT_REQ, fmt.Sprintf("08 %s", xd.UserData.Activity[D.Activity_We_Yound_Scene].ID))) //下一层
		if allInfo.Strength >= 1 {
			xd.ResetTaskByID(proto.S_WE_YOUND_ENTER_REQ)
		}
		return
	}
	if allInfo.Strength > 0 {
		found, moveTo, target := FindNextUncharted(allInfo)
		if found {
			log.Infof("未央仙境-需要移动到: (%02X,%02X) 以探索 (%02X,%02X)", moveTo.X, moveTo.Y, target.X, target.Y)
			xd.Send(proto.Get_Cmd_Data(xd.userInfo.PlayerId, proto.S_WE_YOUND_MOVE_REQ, fmt.Sprintf("08 %s 12 04 08 %02X 10 %02X", xd.UserData.Activity[D.Activity_We_Yound_Scene].ID, moveTo.X, moveTo.Y))) //移动
			time.Sleep(time.Second)
			xd.Send(proto.Get_Cmd_Data(xd.userInfo.PlayerId, proto.S_WE_YOUND_EXPLORE_REQ, fmt.Sprintf("08 %s 12 04 08 %02X 10 %02X", xd.UserData.Activity[D.Activity_We_Yound_Scene].ID, target.X, target.Y))) //探索
			time.Sleep(time.Second)
			xd.Send(proto.Get_Cmd_Data(xd.userInfo.PlayerId, proto.S_WE_YOUND_DEAL_EVENT_REQ, fmt.Sprintf("08 %s 12 04 08 %02X 10 %02X 20 01", xd.UserData.Activity[D.Activity_We_Yound_Scene].ID, target.X, target.Y))) //执行
			//time.Sleep(time.Second)
			//xd.Send(proto.Get_Cmd_Data(xd.userInfo.PlayerId, proto.S_WE_YOUND_RED_POINT_REQ, fmt.Sprintf("08 %s", xd.UserData.Activity[D.Activity_We_Yound_Scene].ID))) //下一层

		} else {
			log.Infof("所有相邻区域已探索完毕")
		}
	}
	if allInfo.Strength < 10 && lefTime >= 0 && lefTime <= 12 && xd.UserData.CondensingFragrance > 0 {
		useNum := int32(10)
		if xd.UserData.CondensingFragrance <= 10 {
			useNum = xd.UserData.CondensingFragrance
		}
		log.Infof("未央仙境-使用%d个凝神香", useNum)
		xd.Send(proto.Get_Cmd_Data(xd.userInfo.PlayerId, proto.S_WE_YOUND_USE_ITEM_REQ, fmt.Sprintf("08 %s 10 E1 B5 06 18 %02X", xd.UserData.Activity[D.Activity_We_Yound_Scene].ID, useNum)))
	}
	if allInfo.Strength >= 1 {
		xd.ResetTaskByID(proto.S_WE_YOUND_ENTER_REQ)
	}
}
